// 2013年版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

package bufio

import (
	"bytes"
	"errors"
	"io"
	"unicode/utf8"
)

// 扫描仪提供了一个方便的接口来读取数据，例如
// 由换行符分隔的文本行组成的文件。连续呼叫
// 扫描方法将跳过文件的“标记”
// 令牌之间的字节。令牌的规范是
// 由SplitFunc类型的拆分函数定义；默认拆分
// 函数将输入拆分为行，并剥离行终止。分裂
// 此包中定义了用于将文件扫描到的函数
// 行、字节、UTF-8编码的符文和空格分隔的字。这个
// 客户端可能会提供一个自定义拆分函数。
// None
// 扫描在EOF、第一个I/O错误或令牌出现时不可恢复地停止
// 大到适合缓冲区。当扫描停止时，读卡器可能会
// 远远超过最后一个标记。需要更多的程序
// 控制错误处理或大型令牌，或必须运行顺序扫描
// 在读卡器上，应该使用bufio.reader。
// None
type Scanner struct {
	r            io.Reader // 客户提供的阅读器。
	split        SplitFunc // 分割令牌的函数。
	maxTokenSize int       // 令牌的最大大小；通过测试进行修改。
	token        []byte    // 拆分返回的最后一个令牌。
	buf          []byte    // 缓冲区用作要拆分的参数。
	start        int       // buf中的第一个未处理字节。
	end          int       // buf中的数据结束。
	err          error     // 粘性错误。
	empties      int       // 连续空令牌的计数。
	scanCalled   bool      // 扫描被调用；缓冲区正在使用中。
	done         bool      // 扫描已完成。
}

// SplitFunc是用于标记的split函数的签名
// 输入参数是剩余未处理参数的初始子字符串
// 数据和一个标记atEOF，用于报告读取器是否没有更多数据
// 给予。返回值是推进输入的字节数
// 以及要返回给用户的下一个令牌（如果有），以及错误（如果有）。
// None
// 如果函数返回错误，扫描将停止，在这种情况下
// 输入可能被丢弃。如果该错误为ErrFinalToken，则扫描
// 停止时没有错误。
// None
// 否则，扫描仪将推进输入。如果令牌不是零，
// 扫描仪将其返回给用户。如果令牌为零，则
// 扫描仪读取更多数据并继续扫描；如果没有了
// 数据——如果atEOF为真——扫描仪返回。如果数据不正确
// 但是，如果没有换行符，则保留完整的令牌
// 扫描行时，SplitFunc可以返回（0，nil，nil）以向
// 扫描仪将更多数据读取到切片中，然后使用
// 从输入中的同一点开始的较长切片。
// None
// 除非atEOF，否则永远不会使用空数据片调用函数
// 这是真的。但是，如果atEOF为真，则数据可能为非空，
// 一如既往，保存未处理的文本。
type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)

// 扫描仪返回的错误。
var (
	ErrTooLong         = errors.New("bufio.Scanner: token too long")
	ErrNegativeAdvance = errors.New("bufio.Scanner: SplitFunc returns negative advance count")
	ErrAdvanceTooFar   = errors.New("bufio.Scanner: SplitFunc returns advance count beyond input")
	ErrBadReadCount    = errors.New("bufio.Scanner: Read returned impossible count")
)

const (
	// MaxScanTokenSize是用于缓冲令牌的最大大小
	// 除非用户使用Scanner.buffer提供显式缓冲区。
	// 实际最大令牌大小可能小于缓冲区大小
	// 可能需要包括，例如，换行符。
	MaxScanTokenSize = 64 * 1024

	startBufSize = 4096 // 缓冲区的初始分配大小。
)

// NewScanner返回一个新的扫描器来读取r。
// 分割函数默认为扫描线。
func NewScanner(r io.Reader) *Scanner {
	return &Scanner{
		r:            r,
		split:        ScanLines,
		maxTokenSize: MaxScanTokenSize,
	}
}

// Err返回扫描仪遇到的第一个非EOF错误。
func (s *Scanner) Err() error {
	if s.err == io.EOF {
		return nil
	}
	return s.err
}

// Bytes返回由扫描调用生成的最新令牌。
// 基础数组可能指向将被覆盖的数据
// 通过后续的扫描调用。它不进行分配。
func (s *Scanner) Bytes() []byte {
	return s.token
}

// Text返回调用Scan生成的最新令牌
// 作为保存其字节的新分配字符串。
func (s *Scanner) Text() string {
	return string(s.token)
}

// ErrFinalToken是一个特殊的sentinel错误值。它的目的是
// 由拆分函数返回，以指示令牌正在被传递
// 错误是最后一个标记，扫描应在此标记之后停止。
// 扫描收到ErrFinalToken后，扫描停止，没有错误。
// 该值对于尽早停止处理或在需要时停止处理非常有用
// 交付最后一个空令牌。人们可以达到同样的行为
// 使用自定义错误值，但在此处提供一个更整洁。
// 有关此值的用法，请参见emptyFinalToken示例。
var ErrFinalToken = errors.New("final token")

// 扫描使扫描程序前进到下一个标记，该标记将
// 可通过Bytes或Text方法获得。当
// 到达输入端或出现错误时，扫描停止。
// 扫描返回false后，Err方法将返回
// 在扫描过程中发生，但如果是io.EOF，则会出现错误
// 将返回零。
// 如果split函数返回太多空值，则扫描会中断
// 不推进输入的令牌。这是一种常见的错误模式
// 扫描仪。
func (s *Scanner) Scan() bool {
	if s.done {
		return false
	}
	s.scanCalled = true
	// 循环直到我们有一个令牌。
	for {
		// 看看我们是否能用我们已经有的东西得到一个代币。
		// 如果数据已用完但出现错误，请给出split函数
		// 有机会恢复任何剩余的，可能是空的令牌。
		if s.end > s.start || s.err != nil {
			advance, token, err := s.split(s.buf[s.start:s.end], s.err != nil)
			if err != nil {
				if err == ErrFinalToken {
					s.token = token
					s.done = true
					return true
				}
				s.setErr(err)
				return false
			}
			if !s.advance(advance) {
				return false
			}
			s.token = token
			if token != nil {
				if s.err == nil || advance > 0 {
					s.empties = 0
				} else {
					// 返回令牌而不是在EOF处推进输入。
					s.empties++
					if s.empties > maxConsecutiveEmptyReads {
						panic("bufio.Scan: too many empty tokens without progressing")
					}
				}
				return true
			}
		}
		// 我们无法使用所持有的内容生成令牌。
		// 如果我们已经遇到EOF或I/O错误，我们就完成了。
		if s.err != nil {
			// 把它关掉。
			s.start = 0
			s.end = 0
			return false
		}
		// 必须读取更多数据。
		// 首先，若有大量的空白，将数据移到缓冲区的开头
		// 或者需要空间。
		if s.start > 0 && (s.end == len(s.buf) || s.start > len(s.buf)/2) {
			copy(s.buf, s.buf[s.start:s.end])
			s.end -= s.start
			s.start = 0
		}
		// 缓冲区满了吗？如果是，请调整大小。
		if s.end == len(s.buf) {
			// 保证在下面的乘法运算中没有溢出。
			const maxInt = int(^uint(0) >> 1)
			if len(s.buf) >= s.maxTokenSize || len(s.buf) > maxInt/2 {
				s.setErr(ErrTooLong)
				return false
			}
			newSize := len(s.buf) * 2
			if newSize == 0 {
				newSize = startBufSize
			}
			if newSize > s.maxTokenSize {
				newSize = s.maxTokenSize
			}
			newBuf := make([]byte, newSize)
			copy(newBuf, s.buf[s.start:s.end])
			s.buf = newBuf
			s.end -= s.start
			s.start = 0
		}
		// 最后，我们可以读取一些输入。确保我们不会陷入困境
		// 行为不端的读者。正式来说，我们不需要这样做，但是让我们
		// 要特别小心：扫描仪用于安全、简单的工作。
		for loop := 0; ; {
			n, err := s.r.Read(s.buf[s.end:len(s.buf)])
			if n < 0 || len(s.buf)-s.end < n {
				s.setErr(ErrBadReadCount)
				break
			}
			s.end += n
			if err != nil {
				s.setErr(err)
				break
			}
			if n > 0 {
				s.empties = 0
				break
			}
			loop++
			if loop > maxConsecutiveEmptyReads {
				s.setErr(io.ErrNoProgress)
				break
			}
		}
	}
}

// advance消耗n个字节的缓冲区。它报告了这笔预付款是否合法。
func (s *Scanner) advance(n int) bool {
	if n < 0 {
		s.setErr(ErrNegativeAdvance)
		return false
	}
	if n > s.end-s.start {
		s.setErr(ErrAdvanceTooFar)
		return false
	}
	s.start += n
	return true
}

// setErr记录遇到的第一个错误。
func (s *Scanner) setErr(err error) {
	if s.err == nil || s.err == io.EOF {
		s.err = err
	}
}

// 缓冲区设置扫描时使用的初始缓冲区和最大值
// None
// 令牌大小是最大值和上限（buf）中的较大值。如果最大值<=上限（buf），
// 扫描将仅使用此缓冲区，不进行分配。
// None
// 默认情况下，扫描使用内部缓冲区并设置
// 最大令牌大小到MaxScanTokenSize。
// None
// 如果在扫描开始后调用缓冲区，则缓冲区会死机。
func (s *Scanner) Buffer(buf []byte, max int) {
	if s.scanCalled {
		panic("Buffer called after Scan")
	}
	s.buf = buf[0:cap(buf)]
	s.maxTokenSize = max
}

// Split设置扫描仪的拆分功能。
// 默认的分割功能是扫描线。
// None
// 如果在扫描开始后调用Split，则会出现恐慌。
func (s *Scanner) Split(split SplitFunc) {
	if s.scanCalled {
		panic("Split called after Scan")
	}
	s.split = split
}

// 分裂函数

// ScanBytes是扫描仪的拆分函数，它将每个字节作为标记返回。
func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}
	return 1, data[0:1], nil
}

var errorRune = []byte(string(utf8.RuneError))

// ScanRunes是扫描仪的拆分函数，它返回每个
// UTF-8编码符文作为令牌。返回的符文序列为
// 相当于输入上的范围循环中的字符串
// 表示错误的UTF-8编码转换为U+FFFD=“\xef\xbf\xbd”。
// 由于扫描接口，这使得客户端无法
// 区分正确编码的替换符文和编码错误。
func ScanRunes(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}

	// 快速路径1:ASCII。
	if data[0] < utf8.RuneSelf {
		return 1, data[0:1], nil
	}

	// 快速路径2：正确的UTF-8解码，无错误。
	_, width := utf8.DecodeRune(data)
	if width > 1 {
		// 这是一个有效的编码。对于正确编码的文件，宽度不能为1
		// 非ASCII符文。
		return width, data[0:width], nil
	}

	// 我们知道这是一个错误：我们有width==1和隐式r==utf8.RuneError。
	// 错误是因为没有完整的符文要解码吗？
	// FullRune正确区分错误编码和不完整编码。
	if !atEOF && !utf8.FullRune(data) {
		// 不完整；获取更多字节。
		return 0, nil, nil
	}

	// 我们有一个真正的UTF-8编码错误。返回正确编码的错误符文
	// 但是只前进一个字节。这与上的范围循环的行为相匹配
	// 编码错误的字符串。
	return 1, errorRune, nil
}

// dropCR从数据中\r删除终端。
func dropCR(data []byte) []byte {
	if len(data) > 0 && data[len(data)-1] == '\r' {
		return data[0 : len(data)-1]
	}
	return data
}

// ScanLines是一个用于扫描仪的拆分函数，它返回扫描的每一行
// 文本，去掉任何行标记的尾端。返回的线路可能会中断
// 空着。行尾标记是一个可选的回车符
// 通过一条强制换行。在正则表达式表示法中，它是“\r？\n”。
// 最后一个非空的输入行将被返回，即使它没有
// 新线。
func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}
	if i := bytes.IndexByte(data, '\n'); i >= 0 {
		// 我们有一个完整的换行终止行。
		return i + 1, dropCR(data[0:i]), nil
	}
	// 如果我们在EOF，我们有一个最终的，非终止线。归还它。
	if atEOF {
		return len(data), dropCR(data), nil
	}
	// 请求更多数据。
	return 0, nil, nil
}

// isSpace报告字符是否为Unicode空白字符。
// 我们避免依赖unicode包，但检查实现的有效性
// 在测试中。
func isSpace(r rune) bool {
	if r <= '\u00FF' {
		// 明显的ASCII字符：\t通过\r加空格。加上两个拉丁语1的怪人。
		switch r {
		case ' ', '\t', '\n', '\v', '\f', '\r':
			return true
		case '\u0085', '\u00A0':
			return true
		}
		return false
	}
	// 高价值的。
	if '\u2000' <= r && r <= '\u200a' {
		return true
	}
	switch r {
	case '\u1680', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000':
		return true
	}
	return false
}

// ScanWords是扫描仪的拆分函数，它返回每个
// 以空格分隔的文字，删除周围的空格。会的
// 永远不要返回空字符串。空间的定义由
// unicode.IsSpace。
func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error) {
	// 跳过前导空格。
	start := 0
	for width := 0; start < len(data); start += width {
		var r rune
		r, width = utf8.DecodeRune(data[start:])
		if !isSpace(r) {
			break
		}
	}
	// 扫描到空格，标记单词的结尾。
	for width, i := 0, start; i < len(data); i += width {
		var r rune
		r, width = utf8.DecodeRune(data[i:])
		if isSpace(r) {
			return i + width, data[start:i], nil
		}
	}
	// 如果我们在EOF，我们有一个最终的，非空的，非终止字。归还它。
	if atEOF && len(data) > start {
		return len(data), data[start:], nil
	}
	// 请求更多数据。
	return start, nil, nil
}
